home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / wprot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-08  |  79.3 KB  |  2,468 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.  
  4.   
  5.    3.26.90      Harry Morris, morris@think.com
  6.    3.30.90  Harry Morris 
  7.    -    removed chunk code from WAISSearchAPDU,
  8.    -    added makeWAISQueryType1Query() and readWAISType1Query() which replace
  9.    makeWAISQueryTerms() and makeWAISQueryDocs().
  10.    4.11.90  HWM - generalized conditional includes (see c-dialect.h)
  11.    - renamed makeWAISType1Query() to makeWAISTextQuery()
  12.    renamed readWAISType1Query() to readWAISTextQuery()
  13.    5.29.90  TS - fixed bug in makeWAISQueryDocs
  14.    added CSTFreeWAISFoo functions
  15. */
  16.  
  17. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  18.  
  19.  
  20. #ifndef lint
  21. static char *RCSid = "$Header: /usr/users/freewais/FreeWAIS-0.1/ir/wprot.c,v 1.1 1993/02/16 15:05:35 freewais Exp $";
  22. #endif
  23.  
  24. /* Change log:
  25.  * $Log: wprot.c,v $
  26.  * Revision 1.1  1993/02/16  15:05:35  freewais
  27.  * Initial revision
  28.  *
  29.  * Revision 1.8  92/04/02  14:20:58  jonathan
  30.  * Backed out last change.
  31.  * 
  32.  * Revision 1.7  92/04/02  09:49:49  jonathan
  33.  * Don't free the doc->type in freeDocObj: it's not a copy!
  34.  * 
  35.  * Revision 1.6  92/02/12  13:57:34  jonathan
  36.  * Added "$Log" so RCS will put the log message in the header
  37.  * 
  38.  * 
  39. */
  40.  
  41. #define _C_WAIS_protocol_
  42.  
  43. /*      This file implements the Z39.50 extensions required for WAIS 
  44. */
  45.  
  46. #include "wprot.h"
  47. #include "cutil.h"
  48. #include "panic.h"
  49. #include <string.h> /* for memmove */
  50.  
  51. #ifndef ANSI_LIKE
  52. #include "ustubs.h"
  53. #endif
  54.  
  55. /* very rough estimates of the size of an object */
  56. #define DefWAISInitResponseSize         (size_t)200
  57. #define DefWAISSearchSize                       (size_t)3000
  58. #define DefWAISSearchResponseSize       (size_t)6000
  59. #define DefWAISPresentSize                      (size_t)1000
  60. #define DefWAISPresentResponseSize      (size_t)6000
  61. #define DefWAISDocHeaderSize            (size_t)500
  62. #define DefWAISShortHeaderSize          (size_t)200
  63. #define DefWAISLongHeaderSize           (size_t)800
  64. #define DefWAISDocTextSize                      (size_t)6000
  65. #define DefWAISDocHeadlineSize          (size_t)500
  66. #define DefWAISDocCodeSize                      (size_t)500
  67.  
  68. #define RESERVE_SPACE_FOR_WAIS_HEADER(len)      \
  69.      if (*len > 0)                                                      \
  70.         *len -= header_len;
  71.  
  72. static char* writeUserInfoHeader _AP((data_tag tag,long infoSize,       
  73.                                       long estHeaderSize,char* buffer,
  74.                                       long* len));
  75.  
  76. static unsigned long userInfoTagSize _AP((data_tag tag,
  77.                                           unsigned long length));
  78.  
  79. /*----------------------------------------------------------------------*/
  80.  
  81. char*
  82. writeInitInfo(init,buffer,len)
  83. InitAPDU* init;
  84. char* buffer;
  85. long* len;
  86. {
  87.   char *userInfo, *buf;
  88.   /* The WAIS protocol doesn't use init info - does now! JG*/
  89.  
  90.   /* older servers barf on this.  Someday we can use it... 
  91.   userInfo = (char *)init->UserInformationField; */
  92.   userInfo = NULL;
  93.  
  94.   if(userInfo != NULL) {
  95.     buf = writeString(userInfo, DT_UserInformationField, buffer, len);
  96.     return(buf);
  97.   }
  98.   else return buffer;
  99. }
  100.  
  101. /*----------------------------------------------------------------------*/
  102.  
  103. static char* readUserInfoHeader _AP((data_tag* tag,unsigned long* num,
  104.                                      char* buffer));
  105.  
  106. char*
  107. readInitInfo(info,buffer)
  108. void** info;
  109. char* buffer;
  110. {
  111.   /* The WAIS protocol doesn't use init info */
  112.   readString((char **)info, buffer);
  113.   return buffer;
  114. }
  115.  
  116. /*----------------------------------------------------------------------*/
  117.  
  118. static unsigned long
  119. userInfoTagSize(tag,length)
  120. data_tag tag;
  121. unsigned long length;
  122. /* return the number of bytes required to write the user info tag and
  123.    length 
  124.  */
  125. {
  126.   unsigned long size;
  127.  
  128.   /* calculate bytes required to represent tag.  max tag is 16K */
  129.   size = writtenCompressedIntSize(tag);
  130.   size += writtenCompressedIntSize(length);
  131.       
  132.   return(size);
  133. }   
  134.  
  135. /*----------------------------------------------------------------------*/
  136.  
  137. static char*
  138. writeUserInfoHeader(tag,infoSize,estHeaderSize,buffer,len)
  139. data_tag tag;
  140. long infoSize;
  141. long estHeaderSize;
  142. char* buffer;
  143. long* len;
  144. /* write the tag and size, making sure the info fits.  return the true end
  145.    of the info (after adjustment) note that the argument infoSize includes
  146.    estHeaderSize.  Note that the argument len is the number of bytes remaining
  147.    in the buffer.  Since we write the tag and size at the begining of the
  148.    buffer (in space that we reserved) we don't want to pass len the calls which
  149.    do that writing. 
  150.  */
  151. {
  152.   long dummyLen = 100;          /* plenty of space for a tag and size */
  153.   char* buf = buffer;
  154.   long realSize = infoSize - estHeaderSize;
  155.   long realHeaderSize = userInfoTagSize(tag,realSize);
  156.  
  157.   if (buffer == NULL || *len == 0)
  158.     return(NULL);
  159.   
  160.   /* write the tag */
  161.   buf = writeTag(tag,buf,&dummyLen);
  162.   
  163.   /* see if the if the header size was correct. if not,
  164.      we have to shift the info to fit the real header size */
  165.   if (estHeaderSize != realHeaderSize)
  166.     {                           /* make sure there is enough space */
  167.       CHECK_FOR_SPACE_LEFT(realHeaderSize - estHeaderSize,len);
  168.       memmove(buffer + realHeaderSize,buffer + estHeaderSize,(size_t)(realSize));
  169.     }
  170.    
  171.   /* write the size */
  172.   writeCompressedInteger(realSize,buf,&dummyLen);
  173.   
  174.   /* return the true end of buffer */
  175.   return(buffer + realHeaderSize + realSize);
  176. }
  177.  
  178. /*----------------------------------------------------------------------*/
  179.  
  180. static char*
  181. readUserInfoHeader(tag,num,buffer)
  182. data_tag* tag;
  183. unsigned long* num;
  184. char* buffer;
  185. /* read the tag and size */
  186. {
  187.   char* buf = buffer;
  188.   buf = readTag(tag,buf);
  189.   buf = readCompressedInteger(num,buf);
  190.   return(buf); 
  191. }
  192.  
  193. /*----------------------------------------------------------------------*/
  194.  
  195. WAISInitResponse* 
  196. makeWAISInitResponse(chunkCode,
  197.                      chunkIDLen,
  198.                      chunkMarker,
  199.                      highlightMarker,
  200.                      deHighlightMarker,
  201.                      newLineChars)
  202. long chunkCode;
  203. long chunkIDLen;
  204. char* chunkMarker;
  205. char* highlightMarker;
  206. char* deHighlightMarker;
  207. char* newLineChars;
  208. /* create a WAIS init response object */
  209. {
  210.   WAISInitResponse* init = (WAISInitResponse*)s_malloc((size_t)sizeof(WAISInitResponse));
  211.  
  212.   init->ChunkCode = chunkCode;  /* note: none are copied! */
  213.   init->ChunkIDLength = chunkIDLen;
  214.   init->ChunkMarker = chunkMarker;
  215.   init->HighlightMarker = highlightMarker;
  216.   init->DeHighlightMarker = deHighlightMarker;
  217.   init->NewlineCharacters = newLineChars;
  218.   
  219.   return(init);
  220. }
  221.  
  222. /*----------------------------------------------------------------------*/
  223.  
  224. void 
  225. freeWAISInitResponse(init)
  226. WAISInitResponse* init;
  227. /* free an object made with makeWAISInitResponse */
  228. {
  229.   s_free(init->ChunkMarker);
  230.   s_free(init->HighlightMarker);
  231.   s_free(init->DeHighlightMarker);
  232.   s_free(init->NewlineCharacters);
  233.   s_free(init);
  234. }
  235.  
  236. /*----------------------------------------------------------------------*/
  237.  
  238. char*
  239. writeInitResponseInfo(init,buffer,len)
  240. InitResponseAPDU* init;
  241. char* buffer;
  242. long* len;
  243. /* write an init response object */
  244. {
  245.   unsigned long header_len = userInfoTagSize(DT_UserInformationLength,
  246.                                              DefWAISInitResponseSize);
  247.   char* buf = buffer + header_len;
  248.   WAISInitResponse* info = (WAISInitResponse*)init->UserInformationField;
  249.   unsigned long size;
  250.   
  251.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  252.     
  253.   buf = writeNum(info->ChunkCode,DT_ChunkCode,buf,len);
  254.   buf = writeNum(info->ChunkIDLength,DT_ChunkIDLength,buf,len);
  255.   buf = writeString(info->ChunkMarker,DT_ChunkMarker,buf,len);
  256.   buf = writeString(info->HighlightMarker,DT_HighlightMarker,buf,len);
  257.   buf = writeString(info->DeHighlightMarker,DT_DeHighlightMarker,buf,len);
  258.   buf = writeString(info->NewlineCharacters,DT_NewlineCharacters,buf,len);
  259.   
  260.   /* now write the header and size */
  261.   size = buf - buffer; 
  262.   buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len);
  263.   
  264.   return(buf);
  265. }
  266.  
  267. /*----------------------------------------------------------------------*/
  268.  
  269. char*
  270. readInitResponseInfo(info,buffer)
  271. void** info;
  272. char* buffer;
  273. /* read an init response object */
  274. {
  275.   char* buf = buffer;
  276.   unsigned long size; 
  277.   unsigned long headerSize;
  278.   data_tag tag;
  279.   long chunkCode,chunkIDLen;
  280.   char* chunkMarker = NULL;
  281.   char* highlightMarker = NULL;
  282.   char* deHighlightMarker = NULL;
  283.   char* newLineChars = NULL;
  284.   
  285.   chunkCode = chunkIDLen = UNUSED;
  286.   
  287.   buf = readUserInfoHeader(&tag,&size,buf);
  288.   headerSize = buf - buffer;
  289.     
  290.   while (buf < (buffer + size + headerSize))
  291.     { data_tag tag = peekTag(buf);
  292.       switch (tag)
  293.         { case DT_ChunkCode:
  294.             buf = readNum(&chunkCode,buf);
  295.             break;
  296.           case DT_ChunkIDLength:
  297.             buf = readNum(&chunkIDLen,buf);
  298.             break;
  299.           case DT_ChunkMarker:
  300.             buf = readString(&chunkMarker,buf);
  301.             break;
  302.           case DT_HighlightMarker:
  303.             buf = readString(&highlightMarker,buf);
  304.             break;
  305.           case DT_DeHighlightMarker:
  306.             buf = readString(&deHighlightMarker,buf);
  307.             break;
  308.           case DT_NewlineCharacters:
  309.             buf = readString(&newLineChars,buf);
  310.             break;
  311.           default:
  312.             s_free(highlightMarker);
  313.             s_free(deHighlightMarker);
  314.             s_free(newLineChars);
  315.             REPORT_READ_ERROR(buf);
  316.             break;
  317.           }
  318.     }
  319.           
  320.   *info = (void *)makeWAISInitResponse(chunkCode,chunkIDLen,chunkMarker,
  321.                                highlightMarker,deHighlightMarker,
  322.                                newLineChars);
  323.   return(buf);
  324. }
  325.  
  326. /*----------------------------------------------------------------------*/
  327.  
  328. WAISSearch* 
  329. makeWAISSearch(seedWords,
  330.                docs,
  331.                textList,
  332.                dateFactor,
  333.                beginDateRange,
  334.                endDateRange,
  335.                maxDocsRetrieved)
  336. char* seedWords;
  337. DocObj** docs;
  338. char** textList;
  339. long dateFactor;
  340. char* beginDateRange;
  341. char* endDateRange;
  342. long maxDocsRetrieved;
  343.  
  344. /* create a type 3 query object */
  345.   WAISSearch* query = (WAISSearch*)s_malloc((size_t)sizeof(WAISSearch));
  346.  
  347.   query->SeedWords = seedWords; /* not copied! */
  348.   query->Docs = docs;           /* not copied! */
  349.   query->TextList = textList;   /* not copied! */
  350.   query->DateFactor = dateFactor;
  351.   query->BeginDateRange = beginDateRange;
  352.   query->EndDateRange = endDateRange;
  353.   query->MaxDocumentsRetrieved = maxDocsRetrieved;
  354.   
  355.   return(query);
  356. }
  357.  
  358. /*----------------------------------------------------------------------*/
  359.  
  360. void 
  361. freeWAISSearch(query)
  362. WAISSearch* query;
  363.  
  364. /* destroy an object made with makeWAISSearch() */
  365. {
  366.   void* ptr = NULL;
  367.   long i;
  368.   
  369.   s_free(query->SeedWords);
  370.   
  371.   if (query->Docs != NULL)
  372.     for (i = 0,ptr = (void *)query->Docs[i]; ptr != NULL; ptr = (void *)query->Docs[++i])
  373.       freeDocObj((DocObj*)ptr);
  374.   s_free(query->Docs);
  375.    
  376.   if (query->TextList != NULL)  /* XXX revisit when textlist is fully defined */
  377.     for (i = 0,ptr = (void *)query->TextList[i]; ptr != NULL; ptr = (void *)query->TextList[++i])
  378.       s_free(ptr);
  379.   s_free(query->TextList);
  380.  
  381.   s_free(query->BeginDateRange);
  382.   s_free(query->EndDateRange);
  383.   s_free(query);
  384. }
  385.  
  386. /*----------------------------------------------------------------------*/
  387.  
  388. DocObj* 
  389. makeDocObjUsingWholeDocument(docID,type)
  390. any* docID;
  391. char* type;
  392.  
  393. /* construct a document object using byte chunks - only for use by
  394.    servers */
  395. {
  396.   DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj));
  397.   doc->DocumentID = docID;              /* not copied! */
  398.   doc->Type = type;             /* not copied! */
  399.   doc->ChunkCode = CT_document;
  400.   return(doc);
  401. }
  402.  
  403. /*----------------------------------------------------------------------*/
  404.  
  405. DocObj* 
  406. makeDocObjUsingLines(docID,type,start,end)
  407. any* docID;
  408. char* type;
  409. long start;
  410. long end;
  411.  
  412. /* construct a document object using line chunks - only for use by
  413.    servers */
  414. {
  415.   DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj));
  416.   doc->ChunkCode = CT_line;
  417.   doc->DocumentID = docID;              /* not copied */
  418.   doc->Type = type;             /* not copied! */
  419.   doc->ChunkStart.Pos = start;
  420.   doc->ChunkEnd.Pos = end;
  421.   return(doc);
  422. }
  423.  
  424. /*----------------------------------------------------------------------*/
  425.  
  426.  
  427. DocObj* 
  428. makeDocObjUsingBytes(docID,type,start,end)
  429. any* docID;
  430. char* type;
  431. long start;
  432. long end;
  433.  
  434. /* construct a document object using byte chunks - only for use by
  435.    servers */
  436. {
  437.   DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj));
  438.   doc->ChunkCode = CT_byte;
  439.   doc->DocumentID = docID;              /* not copied */
  440.   doc->Type = type;             /* not copied! */
  441.   doc->ChunkStart.Pos = start;
  442.   doc->ChunkEnd.Pos = end;
  443.   return(doc);
  444. }
  445.  
  446. /*----------------------------------------------------------------------*/
  447.  
  448. DocObj* 
  449. makeDocObjUsingParagraphs(docID,type,start,end)
  450. any* docID;
  451. char* type;
  452. any* start;
  453. any* end;
  454.  
  455. /* construct a document object using byte chunks - only for use by
  456.    servers */
  457. {
  458.   DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj));
  459.   doc->ChunkCode = CT_paragraph;
  460.   doc->DocumentID = docID;              /* not copied */
  461.   doc->Type = type;
  462.   doc->ChunkStart.ID = start; 
  463.   doc->ChunkEnd.ID = end; 
  464.   return(doc);
  465. }
  466.  
  467. /*----------------------------------------------------------------------*/
  468.  
  469. void
  470. freeDocObj(doc)
  471. DocObj* doc;
  472.  
  473. /* free a docObj */
  474. {
  475.   freeAny(doc->DocumentID);
  476.   s_free(doc->Type);
  477.   if (doc->ChunkCode == CT_paragraph)
  478.     { freeAny(doc->ChunkStart.ID);
  479.       freeAny(doc->ChunkEnd.ID);
  480.     }
  481.   s_free(doc);
  482. }
  483.  
  484. /*----------------------------------------------------------------------*/
  485.  
  486. static char* writeDocObj _AP((DocObj* doc,char* buffer,long* len));
  487.  
  488. static char*
  489. writeDocObj(doc,buffer,len)
  490. DocObj* doc;
  491. char* buffer;
  492. long* len;
  493.  
  494. /* write as little as we can about the doc obj */
  495. {
  496.   char* buf = buffer;
  497.   
  498.   /* we alwasy have to write the id, but its tag depends on if its a chunk */
  499.   if (doc->ChunkCode == CT_document)
  500.     buf = writeAny(doc->DocumentID,DT_DocumentID,buf,len);
  501.   else
  502.     buf = writeAny(doc->DocumentID,DT_DocumentIDChunk,buf,len);
  503.   
  504.   if (doc->Type != NULL)
  505.     buf = writeString(doc->Type,DT_TYPE,buf,len);
  506.   
  507.   switch (doc->ChunkCode)
  508.     { case CT_document:
  509.         /* do nothing - there is no chunk data */
  510.         break;
  511.       case CT_byte:
  512.       case CT_line:
  513.         buf = writeNum(doc->ChunkCode,DT_ChunkCode,buf,len);
  514.         buf = writeNum(doc->ChunkStart.Pos,DT_ChunkStartID,buf,len);
  515.         buf = writeNum(doc->ChunkEnd.Pos,DT_ChunkEndID,buf,len);
  516.         break;
  517.       case CT_paragraph:
  518.         buf = writeNum(doc->ChunkCode,DT_ChunkCode,buf,len);
  519.         buf = writeAny(doc->ChunkStart.ID,DT_ChunkStartID,buf,len);
  520.         buf = writeAny(doc->ChunkEnd.ID,DT_ChunkEndID,buf,len);
  521.         break;
  522.       default:
  523.         panic("Implementation error: unknown chuck type %ld",
  524.               doc->ChunkCode);
  525.         break;
  526.       }
  527.    
  528.   return(buf);
  529. }
  530.  
  531. /*----------------------------------------------------------------------*/
  532.  
  533. static char* readDocObj _AP((DocObj** doc,char* buffer));
  534.  
  535. static char*
  536. readDocObj(doc,buffer)
  537. DocObj** doc;
  538. char* buffer;
  539.  
  540. /* read whatever we have about the new document */
  541. {
  542.   char* buf = buffer;
  543.   data_tag tag;
  544.   
  545.   *doc = (DocObj*)s_malloc((size_t)sizeof(DocObj));
  546.   
  547.   tag = peekTag(buf);
  548.   buf = readAny(&((*doc)->DocumentID),buf);
  549.   
  550.   if (tag == DT_DocumentID)
  551.     { (*doc)->ChunkCode = CT_document;
  552.       tag = peekTag(buf);
  553.       if (tag == DT_TYPE)       /* XXX depends on DT_TYPE != what comes next */
  554.         buf = readString(&((*doc)->Type),buf);
  555.       /* ChunkStart and ChunkEnd are undefined */
  556.     }
  557.   else if (tag == DT_DocumentIDChunk)
  558.     { Boolean readParagraphs = false; /* for cleanup */
  559.       tag = peekTag(buf);
  560.       if (tag == DT_TYPE)       /* XXX depends on DT_TYPE != CT_FOO */
  561.         buf = readString(&((*doc)->Type),buf);
  562.       buf = readNum(&((*doc)->ChunkCode),buf);
  563.       switch ((*doc)->ChunkCode)
  564.         { case CT_byte:
  565.           case CT_line:
  566.             buf = readNum(&((*doc)->ChunkStart.Pos),buf);
  567.             buf = readNum(&((*doc)->ChunkEnd.Pos),buf);
  568.             break;
  569.           case CT_paragraph:
  570.             readParagraphs = true;
  571.             buf = readAny(&((*doc)->ChunkStart.ID),buf);
  572.             buf = readAny(&((*doc)->ChunkEnd.ID),buf);
  573.             break;
  574.           default:
  575.             freeAny((*doc)->DocumentID);
  576.             if (readParagraphs)
  577.               { freeAny((*doc)->ChunkStart.ID);
  578.                 freeAny((*doc)->ChunkEnd.ID);
  579.               }
  580.             s_free(doc);
  581.             REPORT_READ_ERROR(buf);
  582.             break;
  583.           }
  584.     }
  585.   else
  586.     { freeAny((*doc)->DocumentID);
  587.       s_free(*doc);
  588.       REPORT_READ_ERROR(buf);
  589.     }
  590.   return(buf);  
  591. }
  592.  
  593. /*----------------------------------------------------------------------*/
  594.  
  595. char* 
  596. writeSearchInfo(query,buffer,len)
  597. SearchAPDU* query;
  598. char* buffer;
  599. long* len;
  600.  
  601. /* write out a WAIS query (type 1 or 3) */
  602. {
  603.   if (strcmp(query->QueryType,QT_TextRetrievalQuery) == 0)
  604.     { return(writeAny((any*)query->Query,DT_Query,buffer,len));
  605.     }
  606.   else
  607.     { unsigned long header_len = userInfoTagSize(DT_UserInformationLength,
  608.                                                  DefWAISSearchSize); 
  609.       char* buf = buffer + header_len;
  610.       WAISSearch* info = (WAISSearch*)query->Query;
  611.       unsigned long size;
  612.       long i;
  613.   
  614.       RESERVE_SPACE_FOR_WAIS_HEADER(len);
  615.        
  616.       buf = writeString(info->SeedWords,DT_SeedWords,buf,len);
  617.  
  618.       if (info->Docs != NULL)
  619.       { for (i = 0; info->Docs[i] != NULL; i++)
  620.           { buf = writeDocObj(info->Docs[i],buf,len);
  621.           }
  622.         }
  623.    
  624.       /* XXX text list */
  625.  
  626.       buf = writeNum(info->DateFactor,DT_DateFactor,buf,len);
  627.       buf = writeString(info->BeginDateRange,DT_BeginDateRange,buf,len);
  628.       buf = writeString(info->EndDateRange,DT_EndDateRange,buf,len);
  629.       buf = writeNum(info->MaxDocumentsRetrieved,DT_MaxDocumentsRetrieved,buf,len);
  630.   
  631.       /* now write the header and size */
  632.       size = buf - buffer; 
  633.       buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len);
  634.    
  635.       return(buf);
  636.     }
  637. }
  638.  
  639. /*----------------------------------------------------------------------*/
  640.  
  641. char* 
  642. readSearchInfo(info,buffer)
  643. void** info;
  644. char* buffer;
  645.  
  646. /* read a WAIS query (type 1 or 3) */
  647. {
  648.   data_tag type = peekTag(buffer);
  649.   if (type == DT_Query)         /* this is a type 1 query */
  650.     { char* buf = buffer;
  651.       any* query = NULL;
  652.       buf = readAny(&query,buf);
  653.       *info = (void *)query;
  654.       return(buf);
  655.     }
  656.   else                          /* a type 3 query */
  657.     { char* buf = buffer;
  658.       unsigned long size; 
  659.       unsigned long headerSize;
  660.       data_tag tag;
  661.       char* seedWords = NULL;
  662.       char* beginDateRange = NULL;
  663.       char* endDateRange = NULL;
  664.       long dateFactor,maxDocsRetrieved;
  665.       char** textList = NULL; 
  666.       DocObj** docIDs = NULL;
  667.       DocObj* doc = NULL;
  668.       long docs = 0;
  669.       long i;
  670.       void* ptr = NULL;
  671.  
  672.       dateFactor = maxDocsRetrieved = UNUSED;
  673.   
  674.       buf = readUserInfoHeader(&tag,&size,buf);
  675.       headerSize = buf - buffer;
  676.   
  677.       while (buf < (buffer + size + headerSize))
  678.         { data_tag tag = peekTag(buf);
  679.           switch (tag)
  680.             { case DT_SeedWords:
  681.                 buf = readString(&seedWords,buf);
  682.                 break;
  683.               case DT_DocumentID:
  684.               case DT_DocumentIDChunk:
  685.                 if (docIDs == NULL) /* create a new doc list */
  686.                   { docIDs = (DocObj**)s_malloc((size_t)sizeof(DocObj*) * 2);
  687.                   }
  688.                 else            /* grow the doc list */
  689.                   { docIDs = (DocObj**)s_realloc((char*)docIDs,(size_t)(sizeof(DocObj*) * (docs + 2)));
  690.                   }
  691.                 buf = readDocObj(&doc,buf);
  692.                 if (buf == NULL) 
  693.                   { s_free(seedWords);
  694.                     s_free(beginDateRange);
  695.                     s_free(endDateRange);
  696.                     if (docIDs != NULL)
  697.                       for (i = 0,ptr = (void *)docIDs[i]; ptr != NULL; ptr = (void *)docIDs[++i])
  698.                         freeDocObj((DocObj*)ptr);
  699.                     s_free(docIDs);
  700.                     /* XXX should also free textlist when it is fully defined */
  701.                   }
  702.                 RETURN_ON_NULL(buf);
  703.                 docIDs[docs++] = doc; /* put it in the list */
  704.                 docIDs[docs] = NULL;
  705.                 break;
  706.               case DT_TextList:
  707.                 /* XXX */
  708.                 break;
  709.               case DT_DateFactor:
  710.                 buf = readNum(&dateFactor,buf);
  711.                 break;
  712.               case DT_BeginDateRange:
  713.                 buf = readString(&beginDateRange,buf);
  714.                 break;
  715.               case DT_EndDateRange:
  716.                 buf = readString(&endDateRange,buf);
  717.                 break;
  718.               case DT_MaxDocumentsRetrieved:
  719.                 buf = readNum(&maxDocsRetrieved,buf);
  720.                 break;
  721.               default:
  722.                 s_free(seedWords);
  723.                 s_free(beginDateRange);
  724.                 s_free(endDateRange);
  725.                 if (docIDs != NULL)
  726.                   for (i = 0,ptr = (void *)docIDs[i]; ptr != NULL; ptr = (void *)docIDs[++i])
  727.                     freeDocObj((DocObj*)ptr);
  728.                 s_free(docIDs);
  729.                 /* XXX should also free textlist when it is fully defined */
  730.                 REPORT_READ_ERROR(buf);
  731.                 break;
  732.               }
  733.         }
  734.           
  735.       *info = (void *)makeWAISSearch(seedWords,docIDs,textList,
  736.                                      dateFactor,beginDateRange,endDateRange,
  737.                                      maxDocsRetrieved);
  738.       return(buf);
  739.     }
  740. }
  741.  
  742. /*----------------------------------------------------------------------*/
  743.  
  744. WAISDocumentHeader*
  745. makeWAISDocumentHeader(docID,
  746.                        versionNumber,
  747.                        score,
  748.                        bestMatch,
  749.                        docLen,
  750.                        lines,
  751.                        types,
  752.                        source,
  753.                        date,
  754.                        headline,
  755.                        originCity)
  756. any* docID;
  757. long versionNumber;
  758. long score;
  759. long bestMatch;
  760. long docLen;
  761. long lines;
  762. char** types;
  763. char* source;
  764. char* date;
  765. char* headline;
  766. char* originCity;
  767.  
  768. /* construct a standard document header, note that no fields are copied!
  769.    if the application needs to save these fields, it should copy them,
  770.    or set the field in this object to NULL before freeing it.
  771.  */
  772. {
  773.   WAISDocumentHeader* header = 
  774.     (WAISDocumentHeader*)s_malloc((size_t)sizeof(WAISDocumentHeader));
  775.  
  776.   header->DocumentID = docID;
  777.   header->VersionNumber = versionNumber;
  778.   header->Score = score;
  779.   header->BestMatch = bestMatch;
  780.   header->DocumentLength = docLen;
  781.   header->Lines = lines;
  782.   header->Types = types;
  783.   header->Source = source;
  784.   header->Date = date;
  785.   header->Headline = headline;
  786.   header->OriginCity = originCity;
  787.   
  788.   return(header);
  789. }
  790.  
  791. /*----------------------------------------------------------------------*/
  792.  
  793. void
  794. freeWAISDocumentHeader(header)
  795. WAISDocumentHeader* header;
  796.  
  797. {
  798.   freeAny(header->DocumentID);
  799.   doList((void**)header->Types,fs_free); /* can't use the macro here ! */
  800.   s_free(header->Types);
  801.   s_free(header->Source);
  802.   s_free(header->Date);
  803.   s_free(header->Headline);
  804.   s_free(header->OriginCity);
  805.   s_free(header);
  806. }
  807.  
  808. /*----------------------------------------------------------------------*/
  809.  
  810. char*
  811. writeWAISDocumentHeader(header,buffer,len)
  812. WAISDocumentHeader* header;
  813. char* buffer;
  814. long* len;
  815. {
  816.   unsigned long header_len = userInfoTagSize(DT_DocumentHeaderGroup ,
  817.                                              DefWAISDocHeaderSize);
  818.   char* buf = buffer + header_len;
  819.   unsigned long size;
  820.   
  821.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  822.    
  823.   buf = writeAny(header->DocumentID,DT_DocumentID,buf,len);
  824.   buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len);
  825.   buf = writeNum(header->Score,DT_Score,buf,len);
  826.   buf = writeNum(header->BestMatch,DT_BestMatch,buf,len);
  827.   buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len);
  828.   buf = writeNum(header->Lines,DT_Lines,buf,len);
  829.   if (header->Types != NULL)
  830.     { long size;
  831.       char* ptr = NULL;
  832.       long i;
  833.       buf = writeTag(DT_TYPE_BLOCK,buf,len);
  834.       for (i = 0,size = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i])
  835.         { long typeSize = strlen(ptr);
  836.           size += writtenTagSize(DT_TYPE);
  837.           size += writtenCompressedIntSize(typeSize);
  838.           size += typeSize; 
  839.         }
  840.       buf = writeCompressedInteger((unsigned long)size,buf,len);
  841.       for (i = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i])
  842.         buf = writeString(ptr,DT_TYPE,buf,len);
  843.     }
  844.   buf = writeString(header->Source,DT_Source,buf,len);
  845.   buf = writeString(header->Date,DT_Date,buf,len);
  846.   buf = writeString(header->Headline,DT_Headline,buf,len);
  847.   buf = writeString(header->OriginCity,DT_OriginCity,buf,len);
  848.   
  849.   /* now write the header and size */
  850.   size = buf - buffer; 
  851.   buf = writeUserInfoHeader(DT_DocumentHeaderGroup,size,header_len,buffer,len);
  852.  
  853.   return(buf);
  854. }
  855.  
  856. /*----------------------------------------------------------------------*/
  857.  
  858. char*
  859. readWAISDocumentHeader(header,buffer)
  860. WAISDocumentHeader** header;
  861. char* buffer;
  862. {
  863.   char* buf = buffer;
  864.   unsigned long size; 
  865.   unsigned long headerSize;
  866.   data_tag tag;
  867.   any* docID = NULL;
  868.   long versionNumber,score,bestMatch,docLength,lines;
  869.   char** types = NULL;
  870.   char *source = NULL;
  871.   char *date = NULL;
  872.   char *headline = NULL;
  873.   char *originCity = NULL;
  874.   
  875.   versionNumber = score = bestMatch = docLength = lines = UNUSED;
  876.   
  877.   buf = readUserInfoHeader(&tag,&size,buf);
  878.   headerSize = buf - buffer;
  879.     
  880.   while (buf < (buffer + size + headerSize))
  881.     { data_tag tag = peekTag(buf);
  882.       switch (tag)
  883.         { case DT_DocumentID:
  884.             buf = readAny(&docID,buf);
  885.             break;
  886.           case DT_VersionNumber:
  887.             buf = readNum(&versionNumber,buf);
  888.             break;
  889.           case DT_Score:
  890.             buf = readNum(&score,buf);
  891.             break;
  892.           case DT_BestMatch:
  893.             buf = readNum(&bestMatch,buf);
  894.             break;
  895.           case DT_DocumentLength:
  896.             buf = readNum(&docLength,buf);
  897.             break;
  898.           case DT_Lines:
  899.             buf = readNum(&lines,buf);
  900.             break;
  901.           case DT_TYPE_BLOCK:
  902. #ifdef WIN32
  903.             { unsigned long size = 0;
  904. #else
  905.             { unsigned long size = -1;
  906. #endif
  907.               long numTypes = 0;
  908.               buf = readTag(&tag,buf);
  909.               buf = readCompressedInteger(&size,buf);
  910.               while (size > 0)
  911.                 { char* type = NULL;
  912.                   char* originalBuf = buf;
  913.                   buf = readString(&type,buf);
  914.                   types = (char**)s_realloc(types,(size_t)(sizeof(char*) * (numTypes + 2)));
  915.                   types[numTypes++] = type;
  916.                   types[numTypes] = NULL;
  917.                   size -= (buf - originalBuf);
  918.                 }
  919.             }
  920.           case DT_Source:
  921.             buf = readString(&source,buf);
  922.             break;
  923.           case DT_Date:
  924.             buf = readString(&date,buf);
  925.             break;
  926.           case DT_Headline:
  927.             buf = readString(&headline,buf);
  928.             break;
  929.           case DT_OriginCity:
  930.             buf = readString(&originCity,buf);
  931.             break;
  932.           default:
  933.             freeAny(docID);
  934.             s_free(source);
  935.             s_free(date);
  936.             s_free(headline);
  937.             s_free(originCity);
  938.             REPORT_READ_ERROR(buf);
  939.             break;
  940.           }
  941.     }
  942.           
  943.   *header = makeWAISDocumentHeader(docID,versionNumber,score,bestMatch,
  944.                                    docLength,lines,types,source,date,headline,
  945.                                    originCity);
  946.   return(buf);
  947. }
  948.  
  949. /*----------------------------------------------------------------------*/
  950.  
  951. WAISDocumentShortHeader*
  952. makeWAISDocumentShortHeader(docID,
  953.                             versionNumber,
  954.                             score,
  955.                             bestMatch,
  956.                             docLen,
  957.                             lines)
  958. any* docID;
  959. long versionNumber;
  960. long score;
  961. long bestMatch;
  962. long docLen;
  963. long lines;
  964. /* construct a short document header, note that no fields are copied!
  965.    if the application needs to save these fields, it should copy them,
  966.    or set the field in this object to NULL before freeing it.
  967.  */
  968. {
  969.   WAISDocumentShortHeader* header = 
  970.     (WAISDocumentShortHeader*)s_malloc((size_t)sizeof(WAISDocumentShortHeader));
  971.  
  972.   header->DocumentID = docID;
  973.   header->VersionNumber = versionNumber;
  974.   header->Score = score;
  975.   header->BestMatch = bestMatch;
  976.   header->DocumentLength = docLen;
  977.   header->Lines = lines;
  978.   
  979.   return(header);
  980. }
  981.  
  982. /*----------------------------------------------------------------------*/
  983.  
  984. void
  985. freeWAISDocumentShortHeader(header)
  986. WAISDocumentShortHeader* header;
  987. {
  988.   freeAny(header->DocumentID);
  989.   s_free(header);
  990. }
  991.  
  992. /*----------------------------------------------------------------------*/
  993.  
  994. char*
  995. writeWAISDocumentShortHeader(header,buffer,len)
  996. WAISDocumentShortHeader* header;
  997. char* buffer;
  998. long* len;
  999. {
  1000.   unsigned long header_len = userInfoTagSize(DT_DocumentShortHeaderGroup ,
  1001.                                              DefWAISShortHeaderSize);
  1002.   char* buf = buffer + header_len;
  1003.   unsigned long size;
  1004.   
  1005.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  1006.    
  1007.   buf = writeAny(header->DocumentID,DT_DocumentID,buf,len);
  1008.   buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len);
  1009.   buf = writeNum(header->Score,DT_Score,buf,len);
  1010.   buf = writeNum(header->BestMatch,DT_BestMatch,buf,len);
  1011.   buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len);
  1012.   buf = writeNum(header->Lines,DT_Lines,buf,len);
  1013.   
  1014.   /* now write the header and size */
  1015.   size = buf - buffer; 
  1016.   buf = writeUserInfoHeader(DT_DocumentShortHeaderGroup,size,header_len,buffer,len);
  1017.  
  1018.   return(buf);
  1019. }
  1020.  
  1021. /*----------------------------------------------------------------------*/
  1022.  
  1023. char*
  1024. readWAISDocumentShortHeader(header,buffer)
  1025. WAISDocumentShortHeader** header;
  1026. char* buffer;
  1027. {
  1028.   char* buf = buffer;
  1029.   unsigned long size; 
  1030.   unsigned long headerSize;
  1031.   data_tag tag;
  1032.   any* docID = NULL;
  1033.   long versionNumber,score,bestMatch,docLength,lines;
  1034.   
  1035.   versionNumber = score = bestMatch = docLength = lines = UNUSED;
  1036.   
  1037.   buf = readUserInfoHeader(&tag,&size,buf);
  1038.   headerSize = buf - buffer;
  1039.     
  1040.   while (buf < (buffer + size + headerSize))
  1041.     { data_tag tag = peekTag(buf);
  1042.       switch (tag)
  1043.         { case DT_DocumentID:
  1044.             buf = readAny(&docID,buf);
  1045.             break;
  1046.           case DT_VersionNumber:
  1047.             buf = readNum(&versionNumber,buf);
  1048.             break;
  1049.           case DT_Score:
  1050.             buf = readNum(&score,buf);
  1051.             break;
  1052.           case DT_BestMatch:
  1053.             buf = readNum(&bestMatch,buf);
  1054.             break;
  1055.           case DT_DocumentLength:
  1056.             buf = readNum(&docLength,buf);
  1057.             break;
  1058.           case DT_Lines:
  1059.             buf = readNum(&lines,buf);
  1060.             break;
  1061.           default:
  1062.             freeAny(docID);
  1063.             REPORT_READ_ERROR(buf);
  1064.             break;
  1065.           }
  1066.     }
  1067.           
  1068.   *header = makeWAISDocumentShortHeader(docID,versionNumber,score,bestMatch,
  1069.                                         docLength,lines);
  1070.   return(buf);
  1071. }
  1072.  
  1073. /*----------------------------------------------------------------------*/
  1074.  
  1075. WAISDocumentLongHeader*
  1076. makeWAISDocumentLongHeader(docID,
  1077.                            versionNumber,
  1078.                            score,
  1079.                            bestMatch,
  1080.                            docLen,
  1081.                            lines,
  1082.                            types,
  1083.                            source,
  1084.                            date,
  1085.                            headline,
  1086.                            originCity,
  1087.                            stockCodes,
  1088.                            companyCodes,
  1089.                            industryCodes)
  1090. any* docID;
  1091. long versionNumber;
  1092. long score;
  1093. long bestMatch;
  1094. long docLen;
  1095. long lines;
  1096. char** types;
  1097. char* source;
  1098. char* date;
  1099. char* headline;
  1100. char* originCity;
  1101. char* stockCodes;
  1102. char* companyCodes;
  1103. char* industryCodes;
  1104. /* construct a long document header, note that no fields are copied!
  1105.    if the application needs to save these fields, it should copy them,
  1106.    or set the field in this object to NULL before freeing it.
  1107.  */
  1108. {
  1109.   WAISDocumentLongHeader* header = 
  1110.     (WAISDocumentLongHeader*)s_malloc((size_t)sizeof(WAISDocumentLongHeader));
  1111.  
  1112.   header->DocumentID = docID;
  1113.   header->VersionNumber = versionNumber;
  1114.   header->Score = score;
  1115.   header->BestMatch = bestMatch;
  1116.   header->DocumentLength = docLen;
  1117.   header->Lines = lines;
  1118.   header->Types = types;
  1119.   header->Source = source;
  1120.   header->Date = date;
  1121.   header->Headline = headline;
  1122.   header->OriginCity = originCity;
  1123.   header->StockCodes = stockCodes;
  1124.   header->CompanyCodes = companyCodes;
  1125.   header->IndustryCodes = industryCodes;
  1126.   
  1127.   return(header);
  1128. }
  1129.  
  1130. /*----------------------------------------------------------------------*/
  1131.  
  1132. void
  1133. freeWAISDocumentLongHeader(header)
  1134. WAISDocumentLongHeader* header;
  1135. {
  1136.   freeAny(header->DocumentID);
  1137.   doList((void**)header->Types,fs_free); /* can't use the macro here! */
  1138.   s_free(header->Source);
  1139.   s_free(header->Date);
  1140.   s_free(header->Headline);
  1141.   s_free(header->OriginCity);
  1142.   s_free(header->StockCodes);
  1143.   s_free(header->CompanyCodes);
  1144.   s_free(header->IndustryCodes);
  1145.   s_free(header);
  1146. }
  1147.  
  1148. /*----------------------------------------------------------------------*/
  1149.  
  1150. char*
  1151. writeWAISDocumentLongHeader(header,buffer,len)
  1152. WAISDocumentLongHeader* header;
  1153. char* buffer;
  1154. long* len;
  1155. {
  1156.   unsigned long header_len = userInfoTagSize(DT_DocumentLongHeaderGroup ,
  1157.                                              DefWAISLongHeaderSize);
  1158.   char* buf = buffer + header_len;
  1159.   unsigned long size;
  1160.   
  1161.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  1162.    
  1163.   buf = writeAny(header->DocumentID,DT_DocumentID,buf,len);
  1164.   buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len);
  1165.   buf = writeNum(header->Score,DT_Score,buf,len);
  1166.   buf = writeNum(header->BestMatch,DT_BestMatch,buf,len);
  1167.   buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len);
  1168.   buf = writeNum(header->Lines,DT_Lines,buf,len);
  1169.   if (header->Types != NULL)
  1170.     { long size;
  1171.       char* ptr = NULL;
  1172.       long i;
  1173.       buf = writeTag(DT_TYPE_BLOCK,buf,len);
  1174.       for (i = 0,size = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i])
  1175.         { long typeSize = strlen(ptr);
  1176.           size += writtenTagSize(DT_TYPE);
  1177.           size += writtenCompressedIntSize(typeSize);
  1178.           size += typeSize; 
  1179.         }
  1180.       buf = writeCompressedInteger((unsigned long)size,buf,len);
  1181.       for (i = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i])
  1182.         buf = writeString(ptr,DT_TYPE,buf,len);
  1183.     }
  1184.   buf = writeString(header->Source,DT_Source,buf,len);
  1185.   buf = writeString(header->Date,DT_Date,buf,len);
  1186.   buf = writeString(header->Headline,DT_Headline,buf,len);
  1187.   buf = writeString(header->OriginCity,DT_OriginCity,buf,len);
  1188.   buf = writeString(header->StockCodes,DT_StockCodes,buf,len);
  1189.   buf = writeString(header->CompanyCodes,DT_CompanyCodes,buf,len);
  1190.   buf = writeString(header->IndustryCodes,DT_IndustryCodes,buf,len);
  1191.   
  1192.   /* now write the header and size */
  1193.   size = buf - buffer; 
  1194.   buf = writeUserInfoHeader(DT_DocumentLongHeaderGroup,size,header_len,buffer,len);
  1195.  
  1196.   return(buf);
  1197. }
  1198.  
  1199. /*----------------------------------------------------------------------*/
  1200.  
  1201. char*
  1202. readWAISDocumentLongHeader(header,buffer)
  1203. WAISDocumentLongHeader** header;
  1204. char* buffer;
  1205. {
  1206.   char* buf = buffer;
  1207.   unsigned long size; 
  1208.   unsigned long headerSize;
  1209.   data_tag tag;
  1210.   any* docID;
  1211.   long versionNumber,score,bestMatch,docLength,lines;
  1212.   char **types;
  1213.   char *source,*date,*headline,*originCity,*stockCodes,*companyCodes,*industryCodes;
  1214.   
  1215.   docID = NULL;
  1216.   versionNumber = score = bestMatch = docLength = lines = UNUSED;
  1217.   types = NULL;
  1218.   source = date = headline = originCity = stockCodes = companyCodes = industryCodes = NULL;
  1219.   
  1220.   buf = readUserInfoHeader(&tag,&size,buf);
  1221.   headerSize = buf - buffer;
  1222.     
  1223.   while (buf < (buffer + size + headerSize))
  1224.     { data_tag tag = peekTag(buf);
  1225.       switch (tag)
  1226.         { case DT_DocumentID:
  1227.             buf = readAny(&docID,buf);
  1228.             break;
  1229.           case DT_VersionNumber:
  1230.             buf = readNum(&versionNumber,buf);
  1231.             break;
  1232.           case DT_Score:
  1233.             buf = readNum(&score,buf);
  1234.             break;
  1235.           case DT_BestMatch:
  1236.             buf = readNum(&bestMatch,buf);
  1237.             break;
  1238.           case DT_DocumentLength:
  1239.             buf = readNum(&docLength,buf);
  1240.             break;
  1241.           case DT_Lines:
  1242.             buf = readNum(&lines,buf);
  1243.             break;
  1244.           case DT_TYPE_BLOCK:
  1245. #ifdef WIN32
  1246.             { unsigned long size = 0;
  1247. #else
  1248.             { unsigned long size = -1;
  1249. #endif
  1250.               long numTypes = 0;
  1251.               buf = readTag(&tag,buf);
  1252.               readCompressedInteger(&size,buf);
  1253.               while (size > 0)
  1254.                 { char* type = NULL;
  1255.                   char* originalBuf = buf;
  1256.                   buf = readString(&type,buf);
  1257.                   types = (char**)s_realloc(types,(size_t)(sizeof(char*) * (numTypes + 2)));
  1258.                   types[numTypes++] = type;
  1259.                   types[numTypes] = NULL;
  1260.                   size -= (buf - originalBuf);
  1261.                 }
  1262.             }
  1263.           case DT_Source:
  1264.             buf = readString(&source,buf);
  1265.             break;
  1266.           case DT_Date:
  1267.             buf = readString(&date,buf);
  1268.             break;
  1269.           case DT_Headline:
  1270.             buf = readString(&headline,buf);
  1271.             break;
  1272.           case DT_OriginCity:
  1273.             buf = readString(&originCity,buf);
  1274.             break;
  1275.           case DT_StockCodes:
  1276.             buf = readString(&stockCodes,buf);
  1277.             break;
  1278.           case DT_CompanyCodes:
  1279.             buf = readString(&companyCodes,buf);
  1280.             break;
  1281.           case DT_IndustryCodes:
  1282.             buf = readString(&industryCodes,buf);
  1283.             break;
  1284.           default:
  1285.             freeAny(docID);
  1286.             s_free(source);
  1287.             s_free(date);
  1288.             s_free(headline);
  1289.             s_free(originCity);
  1290.             s_free(stockCodes);
  1291.             s_free(companyCodes);
  1292.             s_free(industryCodes);
  1293.             REPORT_READ_ERROR(buf);
  1294.             break;
  1295.           }
  1296.     }
  1297.           
  1298.   *header = makeWAISDocumentLongHeader(docID,versionNumber,score,bestMatch,
  1299.                                        docLength,lines,types,source,date,headline,
  1300.                                        originCity,stockCodes,companyCodes,
  1301.                                        industryCodes);
  1302.   return(buf);
  1303. }
  1304.  
  1305. /*----------------------------------------------------------------------*/
  1306.  
  1307. WAISSearchResponse*
  1308. makeWAISSearchResponse(seedWordsUsed,
  1309.                        docHeaders,
  1310.                        shortHeaders,
  1311.                        longHeaders,
  1312.                        text,
  1313.                        headlines,
  1314.                        codes,
  1315.                        diagnostics)
  1316. char* seedWordsUsed;
  1317. WAISDocumentHeader** docHeaders;
  1318. WAISDocumentShortHeader** shortHeaders;
  1319. WAISDocumentLongHeader** longHeaders;
  1320. WAISDocumentText** text;
  1321. WAISDocumentHeadlines** headlines;
  1322. WAISDocumentCodes** codes;
  1323. diagnosticRecord** diagnostics;
  1324. {
  1325.   WAISSearchResponse* response = (WAISSearchResponse*)s_malloc((size_t)sizeof(WAISSearchResponse));
  1326.   
  1327.   response->SeedWordsUsed = seedWordsUsed;
  1328.   response->DocHeaders = docHeaders;
  1329.   response->ShortHeaders = shortHeaders;
  1330.   response->LongHeaders = longHeaders;
  1331.   response->Text = text;
  1332.   response->Headlines = headlines;
  1333.   response->Codes = codes;
  1334.   response->Diagnostics = diagnostics;
  1335.   
  1336.   return(response);
  1337. }
  1338.  
  1339. /*----------------------------------------------------------------------*/
  1340.  
  1341. void
  1342. freeWAISSearchResponse(response)
  1343. WAISSearchResponse* response;
  1344. {
  1345.   void* ptr = NULL;
  1346.   long i;
  1347.  
  1348.   s_free(response->SeedWordsUsed);
  1349.  
  1350.   if (response->DocHeaders != NULL)
  1351.     for (i = 0,ptr = (void *)response->DocHeaders[i]; ptr != NULL; ptr = (void *)response->DocHeaders[++i])
  1352.       freeWAISDocumentHeader((WAISDocumentHeader*)ptr);
  1353.   s_free(response->DocHeaders);
  1354.    
  1355.   if (response->ShortHeaders != NULL)
  1356.     for (i = 0,ptr = (void *)response->ShortHeaders[i]; ptr != NULL; ptr = (void *)response->ShortHeaders[++i])
  1357.       freeWAISDocumentShortHeader((WAISDocumentShortHeader*)ptr);
  1358.   s_free(response->ShortHeaders);
  1359.    
  1360.   if (response->LongHeaders != NULL)
  1361.     for (i = 0,ptr = (void *)response->LongHeaders[i]; ptr != NULL; ptr = (void *)response->LongHeaders[++i])
  1362.       freeWAISDocumentLongHeader((WAISDocumentLongHeader*)ptr);
  1363.   s_free(response->LongHeaders);
  1364.    
  1365.   if (response->Text != NULL)
  1366.     for (i = 0,ptr = (void *)response->Text[i]; ptr != NULL; ptr = (void *)response->Text[++i])
  1367.       freeWAISDocumentText((WAISDocumentText*)ptr);
  1368.   s_free(response->Text);
  1369.    
  1370.   if (response->Headlines != NULL)
  1371.     for (i = 0,ptr = (void *)response->Headlines[i]; ptr != NULL; ptr = (void *)response->Headlines[++i])
  1372.       freeWAISDocumentHeadlines((WAISDocumentHeadlines*)ptr);
  1373.   s_free(response->Headlines);
  1374.    
  1375.   if (response->Codes != NULL)
  1376.     for (i = 0,ptr = (void *)response->Codes[i]; ptr != NULL; ptr = (void *)response->Codes[++i])
  1377.       freeWAISDocumentCodes((WAISDocumentCodes*)ptr);
  1378.   s_free(response->Codes);
  1379.    
  1380.   if (response->Diagnostics != NULL)
  1381.     for (i = 0,ptr = (void *)response->Diagnostics[i]; ptr != NULL; ptr = (void *)response->Diagnostics[++i])
  1382.       freeDiag((diagnosticRecord*)ptr);
  1383.   s_free(response->Diagnostics);
  1384.   
  1385.   s_free(response);
  1386. }
  1387.  
  1388. /*----------------------------------------------------------------------*/
  1389.  
  1390. char* 
  1391. writeSearchResponseInfo(query,buffer,len)
  1392. SearchResponseAPDU* query;
  1393. char* buffer;
  1394. long* len;
  1395. {
  1396.   unsigned long header_len = userInfoTagSize(DT_UserInformationLength,
  1397.                                              DefWAISSearchResponseSize);
  1398.   char* buf = buffer + header_len;
  1399.   WAISSearchResponse* info = (WAISSearchResponse*)query->DatabaseDiagnosticRecords;
  1400.   unsigned long size;
  1401.   void* header = NULL;
  1402.   long i;
  1403.   
  1404.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  1405.   
  1406.   buf = writeString(info->SeedWordsUsed,DT_SeedWordsUsed,buf,len);
  1407.   
  1408.   /* write out all the headers */
  1409.   if (info->DocHeaders != NULL)
  1410.     { for (i = 0,header = (void *)info->DocHeaders[i]; header != NULL; header = (void *)info->DocHeaders[++i])
  1411.         buf = writeWAISDocumentHeader((WAISDocumentHeader*)header,buf,len);
  1412.       }
  1413.    
  1414.   if (info->ShortHeaders != NULL)
  1415.     { for (i = 0,header = (void *)info->ShortHeaders[i]; header != NULL; header = (void *)info->ShortHeaders[++i])
  1416.         buf = writeWAISDocumentShortHeader((WAISDocumentShortHeader*)header,buf,len);
  1417.       }
  1418.  
  1419.   if (info->LongHeaders != NULL)
  1420.     { for (i = 0,header = (void *)info->LongHeaders[i]; header != NULL; header = (void *)info->LongHeaders[++i])
  1421.         buf = writeWAISDocumentLongHeader((WAISDocumentLongHeader*)header,buf,len);
  1422.       }
  1423.  
  1424.   if (info->Text != NULL)
  1425.     { for (i = 0,header = (void *)info->Text[i]; header != NULL; header = (void *)info->Text[++i])
  1426.         buf = writeWAISDocumentText((WAISDocumentText*)header,buf,len);
  1427.       }
  1428.  
  1429.   if (info->Headlines != NULL)
  1430.     { for (i = 0,header = (void *)info->Headlines[i]; header != NULL; header = (void *)info->Headlines[++i])
  1431.         buf = writeWAISDocumentHeadlines((WAISDocumentHeadlines*)header,buf,len);
  1432.       }
  1433.  
  1434.   if (info->Codes != NULL)
  1435.     { for (i = 0,header = (void *)info->Codes[i]; header != NULL;header = (void *)info->Codes[++i])
  1436.         buf = writeWAISDocumentCodes((WAISDocumentCodes*)header,buf,len);
  1437.       }
  1438.  
  1439.   if (info->Diagnostics != NULL)
  1440.     { for (i = 0, header = (void *)info->Diagnostics[i]; header != NULL; header = (void *)info->Diagnostics[++i])
  1441.         buf = writeDiag((diagnosticRecord*)header,buf,len);
  1442.       }
  1443.    
  1444.   /* now write the header and size */
  1445.   size = buf - buffer; 
  1446.   buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len);
  1447.   
  1448.   return(buf);
  1449. }
  1450.  
  1451. /*----------------------------------------------------------------------*/
  1452.  
  1453. static void
  1454. cleanUpWaisSearchResponse _AP((char* buf,char* seedWordsUsed,
  1455.                                WAISDocumentHeader** docHeaders,
  1456.                                WAISDocumentShortHeader** shortHeaders,
  1457.                                WAISDocumentLongHeader** longHeaders,
  1458.                                WAISDocumentText** text,
  1459.                                WAISDocumentHeadlines** headlines,
  1460.                                WAISDocumentCodes** codes,
  1461.                                diagnosticRecord**diags));
  1462.  
  1463. static void
  1464. cleanUpWaisSearchResponse (buf,seedWordsUsed,docHeaders,shortHeaders,
  1465.                            longHeaders,text,headlines,codes,diags)
  1466. char* buf;
  1467. char* seedWordsUsed;
  1468. WAISDocumentHeader** docHeaders;
  1469. WAISDocumentShortHeader** shortHeaders;
  1470. WAISDocumentLongHeader** longHeaders;
  1471. WAISDocumentText** text;
  1472. WAISDocumentHeadlines** headlines;
  1473. WAISDocumentCodes** codes;
  1474. diagnosticRecord** diags;
  1475. /* if buf is NULL, we have just gotten a read error, and need to clean up 
  1476.    any state we have built.  If not, then everything is going fine, and
  1477.    we should just hang loose
  1478.  */
  1479. {
  1480.   void* ptr = NULL;
  1481.   long i;
  1482.  
  1483.   if (buf == NULL)                                              
  1484.    { s_free(seedWordsUsed);                             
  1485.      if (docHeaders != NULL)                            
  1486.        for (i = 0,ptr = (void *)docHeaders[i]; ptr != NULL; 
  1487.             ptr = (void *)docHeaders[++i])              
  1488.          freeWAISDocumentHeader((WAISDocumentHeader*)ptr);      
  1489.      s_free(docHeaders);                                
  1490.      if (shortHeaders != NULL)  
  1491.        for (i = 0,ptr = (void *)shortHeaders[i]; ptr != NULL;
  1492.             ptr = (void *)shortHeaders[++i])    
  1493.          freeWAISDocumentShortHeader((WAISDocumentShortHeader*)ptr);
  1494.      s_free(shortHeaders);                                              
  1495.      if (longHeaders != NULL)                           
  1496.        for (i = 0,ptr = (void *)longHeaders[i]; ptr != NULL; 
  1497.             ptr = (void *)longHeaders[++i])     
  1498.          freeWAISDocumentLongHeader((WAISDocumentLongHeader*)ptr);
  1499.      s_free(longHeaders);                               
  1500.      if (text != NULL)                                  
  1501.        for (i = 0,ptr = (void *)text[i]; ptr != NULL; ptr = (void *)text[++i])
  1502.          freeWAISDocumentText((WAISDocumentText*)ptr);  
  1503.      s_free(text);                                      
  1504.      if (headlines != NULL)                                     
  1505.        for (i = 0,ptr = (void *)headlines[i]; ptr != NULL;
  1506.             ptr = (void *)headlines[++i])               
  1507.          freeWAISDocumentHeadlines((WAISDocumentHeadlines*)ptr);        
  1508.      s_free(headlines);                                         
  1509.      if (codes != NULL)                              
  1510.        for (i = 0,ptr = (void *)codes[i]; ptr != NULL; 
  1511.             ptr = (void *)codes[++i])                           
  1512.          freeWAISDocumentCodes((WAISDocumentCodes*)ptr);         
  1513.      s_free(codes);                                     
  1514.      if (diags != NULL)                                 
  1515.        for (i = 0,ptr = (void *)diags[i]; ptr != NULL; 
  1516.             ptr = (void *)diags[++i])    
  1517.          freeDiag((diagnosticRecord*)ptr);           
  1518.      s_free(diags);
  1519.    }
  1520. }
  1521.  
  1522. /*----------------------------------------------------------------------*/
  1523.  
  1524. char*
  1525. readSearchResponseInfo(info,buffer)
  1526. void** info;
  1527. char* buffer;
  1528. {
  1529.   char* buf = buffer;
  1530.   unsigned long size; 
  1531.   unsigned long headerSize;
  1532.   data_tag tag;
  1533.   void* header = NULL;
  1534.   WAISDocumentHeader** docHeaders = NULL;
  1535.   WAISDocumentShortHeader** shortHeaders = NULL;
  1536.   WAISDocumentLongHeader** longHeaders = NULL;
  1537.   WAISDocumentText** text = NULL;
  1538.   WAISDocumentHeadlines** headlines = NULL;
  1539.   WAISDocumentCodes** codes = NULL;
  1540.   long numDocHeaders,numLongHeaders,numShortHeaders,numText,numHeadlines;
  1541.   long numCodes;
  1542.   char* seedWordsUsed = NULL;
  1543.   diagnosticRecord** diags = NULL;
  1544.   diagnosticRecord* diag = NULL;
  1545.   long numDiags = 0;
  1546.   
  1547.   numDocHeaders = numLongHeaders = numShortHeaders = numText = numHeadlines = numCodes = 0;
  1548.   
  1549.   buf = readUserInfoHeader(&tag,&size,buf);
  1550.   headerSize = buf - buffer;
  1551.     
  1552.   while (buf < (buffer + size + headerSize))
  1553.    { data_tag tag = peekTag(buf);
  1554.      switch (tag)
  1555.       { case DT_SeedWordsUsed:
  1556.           buf = readString(&seedWordsUsed,buf);
  1557.           break;
  1558.         case DT_DatabaseDiagnosticRecords:
  1559.           if (diags == NULL) /* create a new diag list */
  1560.            { diags = (diagnosticRecord**)s_malloc((size_t)sizeof(diagnosticRecord*) * 2);
  1561.            }
  1562.           else /* grow the diag list */
  1563.            { diags = (diagnosticRecord**)s_realloc((char*)diags,(size_t)(sizeof(diagnosticRecord*) * (numDiags + 2)));
  1564.            }
  1565.           buf = readDiag(&diag,buf);
  1566.           diags[numDiags++] = diag; /* put it in the list */
  1567.           diags[numDiags] = NULL;
  1568.           break;
  1569.         case DT_DocumentHeaderGroup:
  1570.                   if (docHeaders == NULL) /* create a new header list */
  1571.                    { docHeaders = (WAISDocumentHeader**)s_malloc((size_t)sizeof(WAISDocumentHeader*) * 2);
  1572.                    }
  1573.                   else /* grow the doc list */
  1574.                    { docHeaders = (WAISDocumentHeader**)s_realloc((char*)docHeaders,(size_t)(sizeof(WAISDocumentHeader*) * (numDocHeaders + 2)));
  1575.                    }
  1576.                   buf = readWAISDocumentHeader((WAISDocumentHeader**)&header,buf);
  1577.                   cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1578.                   RETURN_ON_NULL(buf);
  1579.                   docHeaders[numDocHeaders++] = 
  1580.                     (WAISDocumentHeader*)header; /* put it in the list */
  1581.                   docHeaders[numDocHeaders] = NULL;
  1582.                   break;
  1583.                 case DT_DocumentShortHeaderGroup:
  1584.                   if (shortHeaders == NULL) /* create a new header list */
  1585.                    { shortHeaders = (WAISDocumentShortHeader**)s_malloc((size_t)sizeof(WAISDocumentShortHeader*) * 2);
  1586.                    }
  1587.                   else /* grow the doc list */
  1588.                    { shortHeaders = (WAISDocumentShortHeader**)s_realloc((char*)shortHeaders,(size_t)(sizeof(WAISDocumentShortHeader*) * (numShortHeaders + 2)));
  1589.                    }
  1590.                   buf = readWAISDocumentShortHeader((WAISDocumentShortHeader**)&header,buf);
  1591.                   cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1592.                   RETURN_ON_NULL(buf);
  1593.                   shortHeaders[numShortHeaders++] = 
  1594.                     (WAISDocumentShortHeader*)header; /* put it in the list */
  1595.                   shortHeaders[numShortHeaders] = NULL;
  1596.                   break;
  1597.                 case DT_DocumentLongHeaderGroup:
  1598.                   if (longHeaders == NULL) /* create a new header list */
  1599.                    { longHeaders = (WAISDocumentLongHeader**)s_malloc((size_t)sizeof(WAISDocumentLongHeader*) * 2);
  1600.                    }
  1601.                   else /* grow the doc list */
  1602.                    { longHeaders = (WAISDocumentLongHeader**)s_realloc((char*)longHeaders,(size_t)(sizeof(WAISDocumentLongHeader*) * (numLongHeaders + 2)));
  1603.                    }
  1604.                   buf = readWAISDocumentLongHeader((WAISDocumentLongHeader**)&header,buf);
  1605.                   cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1606.                   RETURN_ON_NULL(buf);
  1607.                   longHeaders[numLongHeaders++] = 
  1608.                     (WAISDocumentLongHeader*)header; /* put it in the list */
  1609.                   longHeaders[numLongHeaders] = NULL;
  1610.                   break;
  1611.         case DT_DocumentTextGroup:
  1612.                   if (text == NULL) /* create a new list */
  1613.                    { text = (WAISDocumentText**)s_malloc((size_t)sizeof(WAISDocumentText*) * 2);
  1614.                    }
  1615.                   else /* grow the list */
  1616.                    { text = (WAISDocumentText**)s_realloc((char*)text,(size_t)(sizeof(WAISDocumentText*) * (numText + 2)));
  1617.                    }
  1618.                   buf = readWAISDocumentText((WAISDocumentText**)&header,buf);
  1619.                   cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1620.                   RETURN_ON_NULL(buf);
  1621.                   text[numText++] = 
  1622.                     (WAISDocumentText*)header; /* put it in the list */
  1623.                   text[numText] = NULL;
  1624.                   break;
  1625.                 case DT_DocumentHeadlineGroup:
  1626.                   if (headlines == NULL) /* create a new list */
  1627.                    { headlines = (WAISDocumentHeadlines**)s_malloc((size_t)sizeof(WAISDocumentHeadlines*) * 2);
  1628.                    }
  1629.                   else /* grow the list */
  1630.                    { headlines = (WAISDocumentHeadlines**)s_realloc((char*)headlines,(size_t)(sizeof(WAISDocumentHeadlines*) * (numHeadlines + 2)));
  1631.                    }
  1632.                   buf = readWAISDocumentHeadlines((WAISDocumentHeadlines**)&header,buf);
  1633.                   cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1634.                   RETURN_ON_NULL(buf);
  1635.                   headlines[numHeadlines++] = 
  1636.                     (WAISDocumentHeadlines*)header; /* put it in the list */
  1637.                   headlines[numHeadlines] = NULL;
  1638.                   break;
  1639.                 case DT_DocumentCodeGroup:
  1640.                   if (codes == NULL) /* create a new list */
  1641.                    { codes = (WAISDocumentCodes**)s_malloc((size_t)sizeof(WAISDocumentCodes*) * 2);
  1642.                    }
  1643.                   else /* grow the list */
  1644.                    { codes = (WAISDocumentCodes**)s_realloc((char*)codes,(size_t)(sizeof(WAISDocumentCodes*) * (numCodes + 2)));
  1645.                    }
  1646.                   buf = readWAISDocumentCodes((WAISDocumentCodes**)&header,buf);
  1647.                   cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1648.                   RETURN_ON_NULL(buf);
  1649.                   codes[numCodes++] = 
  1650.                     (WAISDocumentCodes*)header; /* put it in the list */
  1651.                   codes[numCodes] = NULL;
  1652.                   break;
  1653.         default:
  1654.           cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags);
  1655.           REPORT_READ_ERROR(buf);
  1656.           break;
  1657.       }
  1658.    }
  1659.           
  1660.   *info = (void *)makeWAISSearchResponse(seedWordsUsed,docHeaders,shortHeaders,
  1661.                                  longHeaders,text,headlines,codes,diags);
  1662.   
  1663.   return(buf);
  1664. }
  1665.  
  1666. /*----------------------------------------------------------------------*/
  1667.  
  1668. WAISDocumentText*
  1669. makeWAISDocumentText(docID,versionNumber,documentText)
  1670. any* docID;
  1671. long versionNumber;
  1672. any* documentText;
  1673. {
  1674.   WAISDocumentText* docText = (WAISDocumentText*)s_malloc((size_t)sizeof(WAISDocumentText));
  1675.  
  1676.   docText->DocumentID = docID;
  1677.   docText->VersionNumber = versionNumber;
  1678.   docText->DocumentText = documentText;
  1679.   
  1680.   return(docText);
  1681. }
  1682.  
  1683. /*----------------------------------------------------------------------*/
  1684.  
  1685. void 
  1686. freeWAISDocumentText(docText)
  1687. WAISDocumentText* docText;
  1688. {
  1689.   freeAny(docText->DocumentID);
  1690.   freeAny(docText->DocumentText);
  1691.   s_free(docText);
  1692. }
  1693.  
  1694. /*----------------------------------------------------------------------*/
  1695.  
  1696. char* 
  1697. writeWAISDocumentText(docText,buffer,len)
  1698. WAISDocumentText* docText;
  1699. char* buffer;
  1700. long* len;
  1701. {
  1702.   unsigned long header_len = userInfoTagSize(DT_DocumentTextGroup,
  1703.                                                                                         DefWAISDocTextSize);
  1704.   char* buf = buffer + header_len;
  1705.   unsigned long size;
  1706.   
  1707.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  1708.  
  1709.   buf = writeAny(docText->DocumentID,DT_DocumentID,buf,len);
  1710.   buf = writeNum(docText->VersionNumber,DT_VersionNumber,buf,len);
  1711.   buf = writeAny(docText->DocumentText,DT_DocumentText,buf,len);
  1712.   
  1713.   /* now write the header and size */
  1714.   size = buf - buffer; 
  1715.   buf = writeUserInfoHeader(DT_DocumentTextGroup,size,header_len,buffer,len);
  1716.  
  1717.   return(buf);
  1718. }
  1719.  
  1720. /*----------------------------------------------------------------------*/
  1721.  
  1722. char* 
  1723. readWAISDocumentText(docText,buffer)
  1724. WAISDocumentText** docText;
  1725. char* buffer;
  1726. {
  1727.   char* buf = buffer;
  1728.   unsigned long size; 
  1729.   unsigned long headerSize;
  1730.   data_tag tag;
  1731.   any *docID,*documentText;
  1732.   long versionNumber;
  1733.   
  1734.   docID = documentText = NULL;
  1735.   versionNumber = UNUSED;
  1736.   
  1737.   buf = readUserInfoHeader(&tag,&size,buf);
  1738.   headerSize = buf - buffer;
  1739.     
  1740.   while (buf < (buffer + size + headerSize))
  1741.    { data_tag tag = peekTag(buf);
  1742.      switch (tag)
  1743.       { case DT_DocumentID:
  1744.                   buf = readAny(&docID,buf);
  1745.                   break;
  1746.                 case DT_VersionNumber:
  1747.                   buf = readNum(&versionNumber,buf);
  1748.                   break;
  1749.                 case DT_DocumentText:
  1750.                   buf = readAny(&documentText,buf);
  1751.                   break;
  1752.         default:
  1753.           freeAny(docID);
  1754.           freeAny(documentText);
  1755.           REPORT_READ_ERROR(buf);
  1756.           break;
  1757.       }
  1758.    }
  1759.           
  1760.   *docText = makeWAISDocumentText(docID,versionNumber,documentText);
  1761.   return(buf);
  1762. }
  1763.  
  1764. /*----------------------------------------------------------------------*/
  1765.  
  1766. WAISDocumentHeadlines*
  1767. makeWAISDocumentHeadlines(docID,
  1768.                           versionNumber,
  1769.                           source,
  1770.                           date,
  1771.                           headline,
  1772.                           originCity)
  1773. any* docID;
  1774. long versionNumber;
  1775. char* source;
  1776. char* date;
  1777. char* headline;
  1778. char* originCity;
  1779. {
  1780.   WAISDocumentHeadlines* docHeadline =
  1781.     (WAISDocumentHeadlines*)s_malloc((size_t)sizeof(WAISDocumentHeadlines));
  1782.  
  1783.   docHeadline->DocumentID = docID;
  1784.   docHeadline->VersionNumber = versionNumber;
  1785.   docHeadline->Source = source;
  1786.   docHeadline->Date = date;
  1787.   docHeadline->Headline = headline;
  1788.   docHeadline->OriginCity = originCity;
  1789.   
  1790.   return(docHeadline);
  1791. }
  1792.  
  1793. /*----------------------------------------------------------------------*/
  1794.  
  1795. void 
  1796. freeWAISDocumentHeadlines(docHeadline)
  1797. WAISDocumentHeadlines* docHeadline;
  1798. {
  1799.   freeAny(docHeadline->DocumentID);
  1800.   s_free(docHeadline->Source);
  1801.   s_free(docHeadline->Date);
  1802.   s_free(docHeadline->Headline);
  1803.   s_free(docHeadline->OriginCity);
  1804.   s_free(docHeadline);
  1805. }
  1806.  
  1807. /*----------------------------------------------------------------------*/
  1808.  
  1809. char* 
  1810. writeWAISDocumentHeadlines(docHeadline,buffer,len)
  1811. WAISDocumentHeadlines* docHeadline;
  1812. char* buffer;
  1813. long* len;
  1814. {
  1815.   unsigned long header_len = userInfoTagSize(DT_DocumentHeadlineGroup,
  1816.                                                                                         DefWAISDocHeadlineSize);
  1817.   char* buf = buffer + header_len;
  1818.   unsigned long size;
  1819.   
  1820.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  1821.  
  1822.   buf = writeAny(docHeadline->DocumentID,DT_DocumentID,buf,len);
  1823.   buf = writeNum(docHeadline->VersionNumber,DT_VersionNumber,buf,len);
  1824.   buf = writeString(docHeadline->Source,DT_Source,buf,len);
  1825.   buf = writeString(docHeadline->Date,DT_Date,buf,len);
  1826.   buf = writeString(docHeadline->Headline,DT_Headline,buf,len);
  1827.   buf = writeString(docHeadline->OriginCity,DT_OriginCity,buf,len);
  1828.   
  1829.   /* now write the header and size */
  1830.   size = buf - buffer; 
  1831.   buf = writeUserInfoHeader(DT_DocumentHeadlineGroup,size,header_len,buffer,len);
  1832.  
  1833.   return(buf);
  1834. }
  1835.  
  1836. /*----------------------------------------------------------------------*/
  1837.  
  1838. char* 
  1839. readWAISDocumentHeadlines(docHeadline,buffer)
  1840. WAISDocumentHeadlines** docHeadline;
  1841. char* buffer;
  1842. {
  1843.   char* buf = buffer;
  1844.   unsigned long size; 
  1845.   unsigned long headerSize;
  1846.   data_tag tag;
  1847.   any* docID;
  1848.   long versionNumber;
  1849.   char *source,*date,*headline,*originCity;
  1850.   
  1851.   docID = NULL;
  1852.   versionNumber = UNUSED;
  1853.   source = date = headline = originCity = NULL;
  1854.   
  1855.   buf = readUserInfoHeader(&tag,&size,buf);
  1856.   headerSize = buf - buffer;
  1857.     
  1858.   while (buf < (buffer + size + headerSize))
  1859.    { data_tag tag = peekTag(buf);
  1860.      switch (tag)
  1861.       { case DT_DocumentID:
  1862.                   buf = readAny(&docID,buf);
  1863.                   break;
  1864.                 case DT_VersionNumber:
  1865.                   buf = readNum(&versionNumber,buf);
  1866.                   break;
  1867.                 case DT_Source:
  1868.                   buf = readString(&source,buf);
  1869.                   break;
  1870.                 case DT_Date:
  1871.                   buf = readString(&date,buf);
  1872.                   break;
  1873.                 case DT_Headline:
  1874.                   buf = readString(&headline,buf);
  1875.                   break;
  1876.                 case DT_OriginCity:
  1877.                   buf = readString(&originCity,buf);
  1878.                   break;
  1879.         default:
  1880.           freeAny(docID);
  1881.           s_free(source);
  1882.           s_free(date);
  1883.           s_free(headline);
  1884.           s_free(originCity);
  1885.           REPORT_READ_ERROR(buf);
  1886.           break;
  1887.       }
  1888.    }
  1889.           
  1890.   *docHeadline = makeWAISDocumentHeadlines(docID,versionNumber,source,date,
  1891.                                                                                headline,originCity);
  1892.   return(buf);
  1893. }
  1894.  
  1895. /*----------------------------------------------------------------------*/
  1896.  
  1897. WAISDocumentCodes*
  1898. makeWAISDocumentCodes(docID,
  1899.                       versionNumber,
  1900.                       stockCodes,
  1901.                       companyCodes,
  1902.                       industryCodes)
  1903. any* docID;
  1904. long versionNumber;
  1905. char* stockCodes;
  1906. char* companyCodes;
  1907. char* industryCodes;
  1908. {
  1909.   WAISDocumentCodes* docCodes = (WAISDocumentCodes*)s_malloc((size_t)sizeof(WAISDocumentCodes));
  1910.  
  1911.   docCodes->DocumentID = docID;
  1912.   docCodes->VersionNumber = versionNumber;
  1913.   docCodes->StockCodes = stockCodes;
  1914.   docCodes->CompanyCodes = companyCodes;
  1915.   docCodes->IndustryCodes = industryCodes;
  1916.   
  1917.   return(docCodes);
  1918. }
  1919.  
  1920. /*----------------------------------------------------------------------*/
  1921.  
  1922. void 
  1923. freeWAISDocumentCodes(docCodes)
  1924. WAISDocumentCodes* docCodes;
  1925. {
  1926.   freeAny(docCodes->DocumentID);
  1927.   s_free(docCodes->StockCodes);
  1928.   s_free(docCodes->CompanyCodes);
  1929.   s_free(docCodes->IndustryCodes);
  1930.   s_free(docCodes);
  1931. }
  1932.  
  1933. /*----------------------------------------------------------------------*/
  1934.  
  1935. char* 
  1936. writeWAISDocumentCodes(docCodes,buffer,len)
  1937. WAISDocumentCodes* docCodes;
  1938. char* buffer;
  1939. long* len;
  1940. {
  1941.   unsigned long header_len = userInfoTagSize(DT_DocumentCodeGroup ,
  1942.                                                                                         DefWAISDocCodeSize);
  1943.   char* buf = buffer + header_len;
  1944.   unsigned long size;
  1945.   
  1946.   RESERVE_SPACE_FOR_WAIS_HEADER(len);
  1947.  
  1948.   buf = writeAny(docCodes->DocumentID,DT_DocumentID,buf,len);
  1949.   buf = writeNum(docCodes->VersionNumber,DT_VersionNumber,buf,len);
  1950.   buf = writeString(docCodes->StockCodes,DT_StockCodes,buf,len);
  1951.   buf = writeString(docCodes->CompanyCodes,DT_CompanyCodes,buf,len);
  1952.   buf = writeString(docCodes->IndustryCodes,DT_IndustryCodes,buf,len);
  1953.   
  1954.   /* now write the header and size */
  1955.   size = buf - buffer; 
  1956.   buf = writeUserInfoHeader(DT_DocumentCodeGroup,size,header_len,buffer,len);
  1957.  
  1958.   return(buf);
  1959. }
  1960.  
  1961. /*----------------------------------------------------------------------*/
  1962.  
  1963. char* 
  1964. readWAISDocumentCodes(docCodes,buffer)
  1965. WAISDocumentCodes** docCodes;
  1966. char* buffer;
  1967. {
  1968.   char* buf = buffer;
  1969.   unsigned long size; 
  1970.   unsigned long headerSize;
  1971.   data_tag tag;
  1972.   any* docID;
  1973.   long versionNumber;
  1974.   char *stockCodes,*companyCodes,*industryCodes;
  1975.   
  1976.   docID = NULL;
  1977.   versionNumber = UNUSED;
  1978.   stockCodes = companyCodes = industryCodes = NULL;
  1979.   
  1980.   buf = readUserInfoHeader(&tag,&size,buf);
  1981.   headerSize = buf - buffer;
  1982.     
  1983.   while (buf < (buffer + size + headerSize))
  1984.    { data_tag tag = peekTag(buf);
  1985.      switch (tag)
  1986.       { case DT_DocumentID:
  1987.                   buf = readAny(&docID,buf);
  1988.                   break;
  1989.                 case DT_VersionNumber:
  1990.                   buf = readNum(&versionNumber,buf);
  1991.                   break;
  1992.                 case DT_StockCodes:
  1993.                   buf = readString(&stockCodes,buf);
  1994.                   break;
  1995.                 case DT_CompanyCodes:
  1996.                   buf = readString(&companyCodes,buf);
  1997.                   break;
  1998.                 case DT_IndustryCodes:
  1999.                   buf = readString(&industryCodes,buf);
  2000.                   break;
  2001.         default:
  2002.           freeAny(docID);
  2003.           s_free(stockCodes);
  2004.           s_free(companyCodes);
  2005.           s_free(industryCodes);
  2006.           REPORT_READ_ERROR(buf);
  2007.           break;
  2008.       }
  2009.    }
  2010.           
  2011.   *docCodes = makeWAISDocumentCodes(docID,versionNumber,stockCodes,
  2012.                                                                         companyCodes,industryCodes);
  2013.   return(buf);
  2014. }
  2015.  
  2016. /*----------------------------------------------------------------------*/
  2017.  
  2018. char* 
  2019. writePresentInfo(present,buffer,len)
  2020. PresentAPDU* present;
  2021. char* buffer;
  2022. long* len;
  2023. {
  2024.   /* The WAIS protocol doesn't use present info */
  2025.   return(buffer);
  2026. }
  2027.  
  2028. /*----------------------------------------------------------------------*/
  2029.  
  2030. char* 
  2031. readPresentInfo(info,buffer)
  2032. void** info;
  2033. char* buffer;
  2034. {
  2035.   /* The WAIS protocol doesn't use present info */
  2036.   *info = NULL;
  2037.   return(buffer);
  2038. }
  2039.  
  2040. /*----------------------------------------------------------------------*/
  2041.  
  2042. char* 
  2043. writePresentResponseInfo(response,buffer,len)
  2044. PresentResponseAPDU* response;
  2045. char* buffer;
  2046. long* len;
  2047. {
  2048.   /* The WAIS protocol doesn't use presentResponse info */
  2049.   return(buffer);
  2050. }
  2051.  
  2052. /*----------------------------------------------------------------------*/
  2053.  
  2054. char* 
  2055. readPresentResponseInfo(info,buffer)
  2056. void** info;
  2057. char* buffer;
  2058. {
  2059.   /* The WAIS protocol doesn't use presentResponse info */
  2060.   *info = NULL;
  2061.   return(buffer);
  2062. }
  2063.  
  2064. /*----------------------------------------------------------------------*/
  2065.  
  2066. /* support for type 1 queries */
  2067.  
  2068. /* new use values (for the chunk types) */
  2069. #define BYTE            "wb"
  2070. #define LINE            "wl"
  2071. #define PARAGRAPH       "wp"
  2072. #define DATA_TYPE       "wt"
  2073.  
  2074. /* WAIS supports the following semantics for type 1 queries:
  2075.        
  2076.      1.  retrieve the header/codes from a document:
  2077.  
  2078.             System_Control_Number = docID
  2079.             Data Type = type (optional)
  2080.             And
  2081.  
  2082.      2.  retrieve a fragment of the text of a document:
  2083.  
  2084.             System_Control_Number = docID
  2085.             Data Type = type (optional)
  2086.             And
  2087.                 Chunk >= start
  2088.                 And
  2089.                 Chunk < end
  2090.                 And
  2091.  
  2092.                 Information from multiple documents may be requested by using 
  2093.                 groups of the above joined by:
  2094.  
  2095.             OR
  2096.  
  2097.                 ( XXX does an OR come after every group but the first, or do they
  2098.               all come at the end? )
  2099.               
  2100.         ( XXX return type could be in the element set)
  2101. */
  2102.  
  2103. static query_term** makeWAISQueryTerms _AP((DocObj** docs));
  2104.    
  2105. static query_term**
  2106. makeWAISQueryTerms(docs)
  2107. DocObj** docs;
  2108. /* given a null terminated list of docObjs, construct the appropriate
  2109.    query of the form given above
  2110.  */
  2111. {
  2112.   query_term** terms = NULL;
  2113.   long numTerms = 0;
  2114.   DocObj* doc = NULL;
  2115.   long i;
  2116.  
  2117.   if (docs == NULL)
  2118.     return((query_term**)NULL);
  2119.  
  2120.   terms = (query_term**)s_malloc((size_t)(sizeof(query_term*) * 1));
  2121.   terms[numTerms] = NULL;
  2122.  
  2123.   /* loop through the docs making terms for them all */
  2124.   for (i = 0,doc = docs[i]; doc != NULL; doc = docs[++i])
  2125.     { any* type = NULL;
  2126.  
  2127.       if (doc->Type != NULL)
  2128.         type = stringToAny(doc->Type);
  2129.  
  2130.       if (doc->ChunkCode == CT_document) /* a whole document */
  2131.         { terms = (query_term**)s_realloc((char*)terms,
  2132.                                           (size_t)(sizeof(query_term*) * 
  2133.                                                    (numTerms + 3 + 1)));
  2134.           terms[numTerms++] = makeAttributeTerm(SYSTEM_CONTROL_NUMBER,
  2135.                                                 EQUAL,IGNORE,IGNORE,
  2136.                                                 IGNORE,IGNORE,doc->DocumentID);
  2137.           if (type != NULL)
  2138.            { terms[numTerms++] = makeAttributeTerm(DATA_TYPE,EQUAL,
  2139.                                                    IGNORE,IGNORE,IGNORE,
  2140.                                                    IGNORE,type);
  2141.              terms[numTerms++] = makeOperatorTerm(AND);
  2142.            }
  2143.           terms[numTerms] = NULL;
  2144.         }
  2145.       else                      /* a document fragment */
  2146.         {       char chunk_att[ATTRIBUTE_SIZE];
  2147.                 any* startChunk = NULL;
  2148.                 any* endChunk = NULL;
  2149.  
  2150.                 terms = (query_term**)s_realloc((char*)terms,
  2151.                                                 (size_t)(sizeof(query_term*) * 
  2152.                                                          (numTerms + 7 + 1)));
  2153.  
  2154.                 switch (doc->ChunkCode)
  2155.                   { case CT_byte:
  2156.                     case CT_line:
  2157.                       { char start[20],end[20];
  2158.                         (doc->ChunkCode == CT_byte) ?
  2159.                           strncpy(chunk_att,BYTE,ATTRIBUTE_SIZE) :
  2160.                         strncpy(chunk_att,LINE,ATTRIBUTE_SIZE); 
  2161.                         sprintf(start,"%ld",doc->ChunkStart.Pos);
  2162.                         startChunk = stringToAny(start);
  2163.                         sprintf(end,"%ld",doc->ChunkEnd.Pos);
  2164.                         endChunk = stringToAny(end);
  2165.                       }
  2166.                       break;
  2167.                     case CT_paragraph:
  2168.                       strncpy(chunk_att,PARAGRAPH,ATTRIBUTE_SIZE);
  2169.                       startChunk = doc->ChunkStart.ID;
  2170.                       endChunk = doc->ChunkEnd.ID;
  2171.                       break;
  2172.                     default:
  2173.                       /* error */
  2174.                       break;
  2175.                     }
  2176.  
  2177.                 terms[numTerms++] = makeAttributeTerm(SYSTEM_CONTROL_NUMBER,
  2178.                                                       EQUAL,IGNORE,IGNORE,
  2179.                                                       IGNORE,
  2180.                                                       IGNORE,doc->DocumentID);
  2181.                 if (type != NULL)
  2182.                  { terms[numTerms++] = makeAttributeTerm(DATA_TYPE,EQUAL,IGNORE,
  2183.                                                          IGNORE,IGNORE,IGNORE,
  2184.                                                          type);
  2185.                    terms[numTerms++] = makeOperatorTerm(AND);
  2186.                  }
  2187.                 terms[numTerms++] = makeAttributeTerm(chunk_att,
  2188.                                                       GREATER_THAN_OR_EQUAL,
  2189.                                                       IGNORE,IGNORE,IGNORE, 
  2190.                                                       IGNORE,
  2191.                                                       startChunk);
  2192.                 terms[numTerms++] = makeOperatorTerm(AND);
  2193.                 terms[numTerms++] = makeAttributeTerm(chunk_att,LESS_THAN,
  2194.                                                       IGNORE,IGNORE,IGNORE,
  2195.                                                       IGNORE,
  2196.                                                       endChunk);
  2197.                 terms[numTerms++] = makeOperatorTerm(AND);
  2198.                 terms[numTerms] = NULL;
  2199.  
  2200.                 if (doc->ChunkCode == CT_byte || doc->ChunkCode == CT_line)
  2201.                   { freeAny(startChunk);
  2202.                     freeAny(endChunk);
  2203.                   }
  2204.               }
  2205.       
  2206.       freeAny(type);
  2207.       
  2208.      if (i != 0) /* multiple independent queries, need a disjunction */
  2209.         { terms = (query_term**)s_realloc((char*)terms,
  2210.                                           (size_t)(sizeof(query_term*) * 
  2211.                                                    (numTerms + 1 + 1)));
  2212.           terms[numTerms++] = makeOperatorTerm(OR);
  2213.           terms[numTerms] = NULL;
  2214.         }
  2215.     }
  2216.  
  2217.   return(terms);
  2218. }
  2219.  
  2220. /*----------------------------------------------------------------------*/
  2221.  
  2222. static DocObj** makeWAISQueryDocs _AP((query_term** terms));
  2223.  
  2224. static DocObj** 
  2225. makeWAISQueryDocs(terms)
  2226. query_term** terms;
  2227. /* given a list of terms in the form given above, convert them to 
  2228.    DocObjs.
  2229.  */
  2230. {
  2231.   query_term* docTerm = NULL;
  2232.   query_term* fragmentTerm = NULL;
  2233.   DocObj** docs = NULL;
  2234.   DocObj* doc = NULL;
  2235.   long docNum,termNum;
  2236.  
  2237.   docNum = termNum = 0;
  2238.   
  2239.   docs = (DocObj**)s_malloc((size_t)(sizeof(DocObj*) * 1));
  2240.   docs[docNum] = NULL;
  2241.  
  2242.   /* translate the terms into DocObjs */
  2243.   while (true)
  2244.     {         
  2245.       query_term* typeTerm = NULL;
  2246.       char* type = NULL;
  2247.       long startTermOffset;
  2248.  
  2249.       docTerm = terms[termNum];
  2250.      
  2251.       if (docTerm == NULL)
  2252.         break;                  /* we're done converting */;
  2253.  
  2254.       typeTerm = terms[termNum + 1]; /* get the lead Term if it exists */
  2255.  
  2256.       if (strcmp(typeTerm->Use,DATA_TYPE) == 0) /* we do have a type */
  2257.        { startTermOffset = 3;   
  2258.          type = anyToString(typeTerm->Term);
  2259.        }
  2260.       else                                      /* no type */
  2261.        { startTermOffset = 1;
  2262.          typeTerm = NULL;
  2263.          type = NULL;
  2264.        }
  2265.  
  2266.       /* grow the doc list */
  2267.       docs = (DocObj**)s_realloc((char*)docs,(size_t)(sizeof(DocObj*) * 
  2268.                                                       (docNum + 1 + 1)));
  2269.  
  2270.       /* figure out what kind of docObj to build - and build it */
  2271.       fragmentTerm = terms[termNum + startTermOffset];
  2272.       if (fragmentTerm != NULL && fragmentTerm->TermType == TT_Attribute)
  2273.         {                       /* build a document fragment */
  2274.           query_term* startTerm = fragmentTerm;
  2275.           query_term* endTerm = terms[termNum + startTermOffset + 2]; 
  2276.  
  2277.           if (strcmp(startTerm->Use,BYTE) == 0) /* a byte chunk */
  2278.             doc = makeDocObjUsingBytes(duplicateAny(docTerm->Term),
  2279.                                        type,
  2280.                                        anyToLong(startTerm->Term),
  2281.                                        anyToLong(endTerm->Term));
  2282.           else if (strcmp(startTerm->Use,LINE) == 0) /* a line chunk */
  2283.             doc = makeDocObjUsingLines(duplicateAny(docTerm->Term),
  2284.                                        type,
  2285.                                        anyToLong(startTerm->Term),
  2286.                                        anyToLong(endTerm->Term));
  2287.           else                  /* a paragraph chunk */
  2288.             doc = makeDocObjUsingParagraphs(duplicateAny(docTerm->Term),
  2289.                                             type,
  2290.                                             duplicateAny(startTerm->Term),
  2291.                                             duplicateAny(endTerm->Term));
  2292.           termNum += (startTermOffset + 4);     /* point to next term */
  2293.         }
  2294.       else                      /* build a full document */
  2295.         { 
  2296.           doc = makeDocObjUsingWholeDocument(duplicateAny(docTerm->Term),
  2297.                                              type);
  2298.           termNum += startTermOffset;   /* point to next term */
  2299.         }
  2300.      
  2301.       docs[docNum++] = doc;     /* insert the new document */
  2302.          
  2303.       docs[docNum] = NULL;      /* keep the doc list terminated */
  2304.  
  2305.          
  2306.       if (terms[termNum] != NULL)
  2307.         termNum++; /* skip the OR operator it necessary */
  2308.       else
  2309.         break; /* we are done */
  2310.     }
  2311.  
  2312.   return(docs);
  2313. }
  2314.  
  2315. /*----------------------------------------------------------------------*/
  2316.  
  2317. any* 
  2318. makeWAISTextQuery(docs)
  2319. DocObj** docs;
  2320. /* given a list of DocObjs, return an any whose contents is the corresponding
  2321.    type 1 query
  2322.  */
  2323. {
  2324.   any *buf = NULL;
  2325.   query_term** terms = NULL;
  2326.   
  2327.   terms = makeWAISQueryTerms(docs);
  2328.   buf = writeQuery(terms);
  2329.   
  2330.   doList((void**)terms,freeTerm);
  2331.   s_free(terms);
  2332.   
  2333.   return(buf);
  2334. }
  2335.  
  2336. /*----------------------------------------------------------------------*/
  2337.  
  2338. DocObj** 
  2339. readWAISTextQuery(buf)
  2340. any* buf;
  2341. /* given an any whose contents are type 1 queries of the WAIS sort, 
  2342.    construct a list of the corresponding DocObjs
  2343.  */
  2344. {
  2345.   query_term** terms = NULL;
  2346.   DocObj** docs = NULL;
  2347.   
  2348.   terms = readQuery(buf);
  2349.   docs = makeWAISQueryDocs(terms);
  2350.   
  2351.   doList((void**)terms,freeTerm);
  2352.   s_free(terms);
  2353.   
  2354.   return(docs);
  2355. }
  2356.  
  2357. /*----------------------------------------------------------------------*/
  2358. /* Customized free WAIS object routines:                                */
  2359. /*                                                                      */
  2360. /*   This set of procedures is for applications to free a WAIS object   */
  2361. /*   which was made with makeWAISFOO.                                   */
  2362. /*   Each procedure frees only the memory that was allocated in its     */
  2363. /*   associated makeWAISFOO routine, thus it's not necessary for the    */
  2364. /*   caller to assign nulls to the pointer fields of the WAIS object.  */
  2365. /*----------------------------------------------------------------------*/
  2366.  
  2367. void 
  2368. CSTFreeWAISInitResponse(init)
  2369. WAISInitResponse* init;
  2370. /* free an object made with makeWAISInitResponse */
  2371. {
  2372.   s_free(init);
  2373. }
  2374.  
  2375. /*----------------------------------------------------------------------*/
  2376.  
  2377. void 
  2378. CSTFreeWAISSearch(query)
  2379. WAISSearch* query;
  2380. /* destroy an object made with makeWAISSearch() */
  2381.   s_free(query);
  2382. }
  2383.  
  2384. /*----------------------------------------------------------------------*/
  2385.  
  2386. void
  2387. CSTFreeDocObj(doc)
  2388. DocObj* doc;
  2389. /* free a docObj */
  2390.     s_free(doc);
  2391. }
  2392.  
  2393. /*----------------------------------------------------------------------*/
  2394.  
  2395. void
  2396. CSTFreeWAISDocumentHeader(header)
  2397. WAISDocumentHeader* header;
  2398.     s_free(header);
  2399. }
  2400.  
  2401. /*----------------------------------------------------------------------*/
  2402.  
  2403. void
  2404. CSTFreeWAISDocumentShortHeader(header)
  2405. WAISDocumentShortHeader* header;
  2406.   s_free(header);
  2407. }
  2408. /*----------------------------------------------------------------------*/
  2409.  
  2410. void
  2411. CSTFreeWAISDocumentLongHeader(header)
  2412. WAISDocumentLongHeader* header;
  2413. {
  2414.   s_free(header);
  2415. }
  2416.  
  2417. /*----------------------------------------------------------------------*/
  2418.  
  2419. void
  2420. CSTFreeWAISSearchResponse(response)
  2421. WAISSearchResponse* response;
  2422.   s_free(response);
  2423. }
  2424.  
  2425. /*----------------------------------------------------------------------*/
  2426.  
  2427. void 
  2428. CSTFreeWAISDocumentText(docText)
  2429. WAISDocumentText* docText;
  2430.   s_free(docText);
  2431. }
  2432.  
  2433. /*----------------------------------------------------------------------*/
  2434.  
  2435. void 
  2436. CSTFreeWAISDocumentHeadlines(docHeadline)
  2437. WAISDocumentHeadlines* docHeadline;
  2438.   s_free(docHeadline);
  2439. }
  2440.  
  2441. /*----------------------------------------------------------------------*/
  2442.  
  2443. void 
  2444. CSTFreeWAISDocumentCodes(docCodes)
  2445. WAISDocumentCodes* docCodes;
  2446. {
  2447.   s_free(docCodes);
  2448. }
  2449.  
  2450. /*----------------------------------------------------------------------*/
  2451.  
  2452. void 
  2453. CSTFreeWAISTextQuery(query)
  2454. any* query;
  2455. {
  2456.    freeAny(query);
  2457. }
  2458.  
  2459. /*----------------------------------------------------------------------*/
  2460.